
package com.kweative.model.query;

import com.kweative.model.Index;
import com.kweative.model.Table;
import com.kweative.model.exception.ColumnNotFoundException;
import com.kweative.model.column.Column;
import com.kweative.model.column.IColumn;
import java.util.ArrayList;
import java.util.LinkedList;

/**
 *
 * @author henrik
 */
abstract public class WhereStatement<S extends WhereStatement,T extends Table> extends Statement<T> {
    LinkedList<WherePhrase<S>> wherePhrases = new LinkedList<WherePhrase<S>>();
    LinkedList<JoinPhrase> joinPhrases = new LinkedList<JoinPhrase>();
    LinkedList<OrderPhrase> orderPhrases = new LinkedList<OrderPhrase>();
    LinkedList<Column> groupCols = new LinkedList<Column>();
    
    private int limit = -1;
    private int offset = -1;

    public WhereStatement(T primTable) {
        super(primTable);
    }

    public S row(int primary) {
        where(getTable().getPrimaryColumn()).isEqual(primary);
        return (S) this;
    }
    public S using(Index index,Object ... values) {
        ArrayList<IColumn> cols = index.getColumns();
        for(int i = 0; i < values.length;i++) {
            where((Column)cols.get(i)).isEqual(values[i]);
        }
        return (S) this;
    }
    public WherePhrase<S> where(Column<?,T> col) {
        WherePhrase<S> where =  new WherePhrase<S>(col,this);
        wherePhrases.add(where);
        return where;
    }
    public <J extends Table> OnStatement<J,WhereStatement<S,T>> join(J table,JoinType type) {
        JoinPhrase join =  new JoinPhrase(table,this,type);
        joinPhrases.add(join);
        return join.on();
    }
    public <J extends Table> OnStatement<J,WhereStatement<S,T>> join(J table) {
        return join(table,JoinType.INNER);
    }

    public S orderBy(Column col,Order order) {
        orderPhrases.add(new OrderPhrase(col, order));
        return (S) this;
    }
    public S groupBy(Column col) {
        groupCols.add(col);
        return (S) this;
    }
    public S limit(int offset,int limit) {
        this.offset = offset;
        this.limit = limit;
        return (S) this;
    }
    public S limit(int limit) {
        return limit(-1,limit);
    }
    public S limitPage(int page,int rowsPrPage) {
        return limit(page*rowsPrPage,rowsPrPage);
    }
    protected String compileJoinPhrase() {
        StringBuilder sb = new StringBuilder();
        
        for(int i = 0; i < joinPhrases.size();i++) {
            sb.append(joinPhrases.get(i).toString());
        }
        return sb.toString();
    }
    protected String compileGroupPhrase()  {
        StringBuilder sb = new StringBuilder();
        if (groupCols.size() > 0)
            sb.append(" GROUP BY ");
        boolean first = true;
        for(int i = 0; i < groupCols.size();i++) {
            if (!first) sb.append(',');
            sb.append(QueryUtil.formatColumn(groupCols.get(i)));
            first = false;
        }

        return sb.toString();
    }
    protected String compileOrderPhrase()  {
        StringBuilder sb = new StringBuilder();
        if (orderPhrases.size() > 0)
            sb.append(" ORDER BY ");
        boolean first = true;
        for(int i = 0; i < orderPhrases.size();i++) {
            if (!first) sb.append(',');
            sb.append(orderPhrases.get(i).toString());
            first = false;
        }

        return sb.toString();
    }
    protected String compileLimitPhrase() {
        StringBuilder sb = new StringBuilder();
        if (offset > -1 || limit > -1) {
            if (offset > -1 && limit > -1)
                sb.append(" LIMIT ").append(offset).append(",").append(limit);
            else
                sb.append(" LIMIT ").append(limit);
        }
        return sb.toString();
    }
    protected String compileWherePhrase() throws ColumnNotFoundException {
        StringBuilder sb = new StringBuilder();
        boolean first = true;
        for(int i = 0; i < wherePhrases.size();i++) {
            WherePhrase<S> phrase = wherePhrases.get(i);
            sb.append((first) ? "(" : ") AND (")
                .append(QueryUtil.formatColumn(phrase.getColumn()))
                .append(phrase.toString());
            first = false;
        }
        if (!first)
            sb.append(")");
        return sb.toString();
    }

    public enum Order {
        ASCENDING,
        DESCENDING
    }
}
